#include <stddef.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <vector>
#include <string>

#include "n2base.h"
#include "Dumper.h"

void dump_elf_file(FILE *fp, const char* filename)
{
    unsigned char detechbuf[8];
    long long filesize;

    filesize = dpGetFileSize(fp);
    dpSetDumppingFileSize(filesize);
    dpSetDumppingFileName(filename);
    memset(detechbuf, 0xff, sizeof(detechbuf));

    // detech ELF file flag
    fread(detechbuf, 1, 8, fp);
    fseek(fp, 0, SEEK_SET);
    if (detechbuf[0]==0x7f && detechbuf[1]==0x45 && detechbuf[2]==0x4c && detechbuf[3]==0x46)       // !ELF
    {
        dpSetDumppingFilePart(0, filesize);
        _dump_elf_filepart(fp, 0);
    }
    else if (detechbuf[0]==0x21 && detechbuf[1]==0x3c && detechbuf[2]==0x61 && detechbuf[3]==0x72 &&
        detechbuf[4]==0x63 && detechbuf[5]==0x68 && detechbuf[6]==0x3e && detechbuf[7]==0x0a)   // !<ARCH>\n 
    {

    }
    else
    {

    }
}

typedef unsigned long long      Elf64_Addr;
typedef unsigned long long      Elf64_Off;
typedef unsigned short          Elf64_Half;
typedef unsigned int            Elf64_Word;
typedef signed int              Elf64_Sword;
typedef unsigned long long      Elf64_Xword;
typedef signed long long        Elf64_Sxword;

typedef unsigned int            Elf32_Addr;
typedef unsigned int            Elf32_Off;
typedef unsigned short          Elf32_Half;
typedef signed int              Elf32_Sword;
typedef unsigned int            Elf32_Word;

#define CLASS_ELF32             1
#define CLASS_ELF64             2

#define EI_NIDENT 16
typedef struct {
    unsigned char   e_ident[EI_NIDENT];
    Elf32_Half      e_type;
    Elf32_Half      e_machine;
    Elf32_Word      e_version;
    Elf32_Addr      e_entry;
    Elf32_Off       e_phoff;
    Elf32_Off       e_shoff;
    Elf32_Word      e_flags;
    Elf32_Half      e_ehsize;
    Elf32_Half      e_phentsize;
    Elf32_Half      e_phnum;
    Elf32_Half      e_shentsize;
    Elf32_Half      e_shnum;
    Elf32_Half      e_shstrndx;
} Elf32_Ehdr;

typedef struct
{
    unsigned char   e_ident[EI_NIDENT];     // ELF identification 
    Elf64_Half      e_type;                 // Object file type 
    Elf64_Half      e_machine;              // Machine type 
    Elf64_Word      e_version;              // Object file version 
    Elf64_Addr      e_entry;                // Entry point address 
    Elf64_Off       e_phoff;                // Program header offset 
    Elf64_Off       e_shoff;                // Section header offset 
    Elf64_Word      e_flags;                // Processor-specific flags 
    Elf64_Half      e_ehsize;               // ELF header size 
    Elf64_Half      e_phentsize;            // Size of program header entry 
    Elf64_Half      e_phnum;                // Number of program header entries 
    Elf64_Half      e_shentsize;            // Size of section header entry 
    Elf64_Half      e_shnum;                // Number of section header entries 
    Elf64_Half      e_shstrndx;             // Section name string table index 
} Elf64_Ehdr;

typedef union {
    unsigned char   e_ident[EI_NIDENT];
    struct {
        unsigned char   elf_flag[4];
        unsigned char   Class;
        unsigned char   endian;
        unsigned char   elf_version;
        unsigned char   os_abi;
        unsigned char   abi_version;
    } flag;
}elf_ident_t;

typedef struct {
    Elf32_Word  sh_name;
    Elf32_Word  sh_type;
    Elf32_Word  sh_flags;
    Elf32_Addr  sh_addr;
    Elf32_Off   sh_offset;
    Elf32_Word  sh_size;
    Elf32_Word  sh_link;
    Elf32_Word  sh_info;
    Elf32_Word  sh_addralign;
    Elf32_Word  sh_entsize;
} Elf32_Shdr;

typedef struct
{
    Elf64_Word  sh_name;            // Section name 
    Elf64_Word  sh_type;            // Section type 
    Elf64_Xword sh_flags;           // Section attributes 
    Elf64_Addr  sh_addr;            // Virtual address in memory 
    Elf64_Off   sh_offset;          // Offset in file 
    Elf64_Xword sh_size;            // Size of section 
    Elf64_Word  sh_link;            // Link to other section 
    Elf64_Word  sh_info;            // Miscellaneous information 
    Elf64_Xword sh_addralign;       // Address alignment boundary 
    Elf64_Xword sh_entsize;         // Size of entries, if section has table 
} Elf64_Shdr;

typedef struct {
    Elf32_Word  p_type;
    Elf32_Off   p_offset;
    Elf32_Addr  p_vaddr;
    Elf32_Addr  p_paddr;
    Elf32_Word  p_filesz;
    Elf32_Word  p_memsz;
    Elf32_Word  p_flags;
    Elf32_Word  p_align;
} Elf32_Phdr;

typedef struct
{
    Elf64_Word  p_type;             // Type of segment
    Elf64_Word  p_flags;            // Segment attributes
    Elf64_Off   p_offset;           // Offset in file
    Elf64_Addr  p_vaddr;            // Virtual address in memory
    Elf64_Addr  p_paddr;            // Reserved
    Elf64_Xword p_filesz;           // Size of segment in file
    Elf64_Xword p_memsz;            // Size of segment in memory
    Elf64_Xword p_align;            // Alignment of segment
} Elf64_Phdr;

typedef struct
{
    Elf64_Sxword d_tag;
    union {
        Elf64_Xword d_val;
        Elf64_Addr d_ptr;
    } d_un;
} Elf64_Dyn;

static void dpReadElfHeader(FILE *fp);
static void dpReadElfSectionHeader(FILE *fp);
static void dpReadElfProgramHeader(FILE *fp);
static void dpReadElfProgramDynlinkEntry(FILE* fp);
static const char* dpGetElfAbiName(unsigned char abi);
static const char * dpGetElfCpuName(unsigned short machine);

static elf_ident_t  ident;
static Elf64_Ehdr   elf_Header;
//static Elf32_Shdr*  elf32_sechdr = NULL;
static Elf64_Shdr*  elf64_sechdr = NULL;
static Elf64_Phdr*  elf64_prohdr = NULL;

void _dump_elf_filepart(FILE* fp, int embed) 
{
    if (!embed) 
        n2print("%s : %s\n", dpstr(S_n2dumper_dumpping_filename), dpGetDumppingFileName());
    n2print("%s: %s (ELF)\n\n", dpstr(S_n2dumper_FileType), dpstr(S_n2dumper_Executable_and_Linking_Format));
    dpReadElfHeader(fp);
    dpReadElfSectionHeader(fp);
    dpReadElfProgramHeader(fp);
    dpReadElfProgramDynlinkEntry(fp);
}

static void dpReadElfHeader(FILE *fp)
{
    int i;
    Elf64_Ehdr  head64;
    Elf32_Ehdr  head32;
    n2print("%s:\n", dpstr(S_n2dumper_ELF_Header));

    // read ident
    dp_fread(&ident, 1, sizeof(ident), fp);
    // show ident array
    n2print("%s", dpstr(S_n2dumper_ELF_ident));
    for (i = 0; i < EI_NIDENT; i++)
        n2print("0x%02x ", ident.e_ident[i]);
    n2print("\n");

    // 32-bit ELF or 64-bit ELF
    if (ident.flag.Class == CLASS_ELF32)
        n2print("%s32-bit ELF\n", dpstr(S_n2dumper_ident_class));                           // ELF32
    else if  (ident.flag.Class == CLASS_ELF64)
        n2print("%s64-bit ELF\n", dpstr(S_n2dumper_ident_class));                           // ELF64
    else
        n2print("%s%s\n", dpstr(S_n2dumper_ident_class), dpstr(S_n2dumper_unknown));

    // endian
    if (ident.flag.endian == 1) {
        n2print("%s%s\n", dpstr(S_n2dumper_ident_data), dpstr(S_n2dumper_Little_Endian));   // little-endian
        dpSetFileFormatLittleEndian(true);
    }
    else if (ident.flag.endian == 2) {
        n2print("%s%s\n", dpstr(S_n2dumper_ident_data), dpstr(S_n2dumper_Big_Endian));      // big-endian
        dpSetFileFormatLittleEndian(false);
    }
    else
        n2print("%s%s\n", dpstr(S_n2dumper_ident_data), dpstr(S_n2dumper_unknown));

    // ELF format version
    n2print("%s%d\n", dpstr(S_n2dumper_ident_ver), ident.flag.elf_version);

    // ABI type
    const char * abiname = dpGetElfAbiName(ident.flag.os_abi);
    if (abiname != NULL)
        n2print("%s%s\n", dpstr(S_n2dumper_ident_osabi), abiname);
    else
        n2print("%s0x%02x (%s)\n", dpstr(S_n2dumper_ident_osabi), ident.flag.os_abi, dpstr(S_n2dumper_unknown));

    // ABI version
    n2print("%s%d\n", dpstr(S_n2dumper_ident_abiver), ident.flag.abi_version);

    // read ELF Header
    memcpy(&elf_Header.e_ident, &ident, EI_NIDENT);
    if (ident.flag.Class == CLASS_ELF32) {
        dp_fread(&head32.e_type, 1, sizeof(Elf32_Ehdr)-EI_NIDENT, fp);
        elf_Header.e_type = dpAutoSwap16(head32.e_type);
        elf_Header.e_machine = dpAutoSwap16(head32.e_machine);
        elf_Header.e_version = dpAutoSwap32(head32.e_version);
        elf_Header.e_entry = dpAutoSwap64((Elf64_Addr)head32.e_entry);
        elf_Header.e_phoff = dpAutoSwap64((Elf64_Off)head32.e_phoff);
        elf_Header.e_shoff = dpAutoSwap64((Elf64_Off)head32.e_shoff);
        elf_Header.e_flags = dpAutoSwap32(head32.e_flags);
        elf_Header.e_ehsize = dpAutoSwap16(head32.e_ehsize);
        elf_Header.e_phentsize = dpAutoSwap16(head32.e_phentsize);
        elf_Header.e_phnum = dpAutoSwap16(head32.e_phnum);
        elf_Header.e_shentsize = dpAutoSwap16(head32.e_shentsize);
        elf_Header.e_shnum = dpAutoSwap16(head32.e_shnum);
        elf_Header.e_shstrndx = dpAutoSwap16(head32.e_shstrndx);
    }
    else if (ident.flag.Class == CLASS_ELF64) {
        dp_fread(&head64.e_type, 1, sizeof(Elf64_Ehdr)-EI_NIDENT, fp);
        elf_Header.e_type = dpAutoSwap16(head64.e_type);
        elf_Header.e_machine = dpAutoSwap16(head64.e_machine);
        elf_Header.e_version = dpAutoSwap32(head64.e_version);
        elf_Header.e_entry = dpAutoSwap64(head64.e_entry);
        elf_Header.e_phoff = dpAutoSwap64(head64.e_phoff);
        elf_Header.e_shoff = dpAutoSwap64(head64.e_shoff);
        elf_Header.e_flags = dpAutoSwap32(head64.e_flags);
        elf_Header.e_ehsize = dpAutoSwap16(head64.e_ehsize);
        elf_Header.e_phentsize = dpAutoSwap16(head64.e_phentsize);
        elf_Header.e_phnum = dpAutoSwap16(head64.e_phnum);
        elf_Header.e_shentsize = dpAutoSwap16(head64.e_shentsize);
        elf_Header.e_shnum = dpAutoSwap16(head64.e_shnum);
        elf_Header.e_shstrndx = dpAutoSwap16(head64.e_shstrndx);
    }
    else {
        n2print("%s: %s\n", dpstr(S_n2dumper_Error), dpstr(S_n2dumper_Unknown_Elf_Format));
        throw DpEx_UnknownElfFormat;                // unknown ELF format
    }
    
    // object type
    if (elf_Header.e_type == 0)
        n2print("%s%s\n", dpstr(S_n2dumper_e_type), dpstr(S_n2dumper_unknown));
    else if (elf_Header.e_type == 1)
        n2print("%s%s\n", dpstr(S_n2dumper_e_type), dpstr(S_n2dumper_Relocatable_object_file));     // obj
    else if (elf_Header.e_type == 2)
        n2print("%s%s\n", dpstr(S_n2dumper_e_type), dpstr(S_n2dumper_Executable_file));             // exe
    else if (elf_Header.e_type == 3)
        n2print("%s%s\n", dpstr(S_n2dumper_e_type), dpstr(S_n2dumper_Shared_object_file));          // so
    else if (elf_Header.e_type == 4)
        n2print("%s%s\n", dpstr(S_n2dumper_e_type), dpstr(S_n2dumper_Core_file));                   // core file
    else if (elf_Header.e_type >= 0xfe00 && elf_Header.e_type <= 0xfeff)
        n2print("%s%s\n", dpstr(S_n2dumper_e_type), dpstr(S_n2dumper_Environment_specific_use));
    else if (elf_Header.e_type >= 0xff00 && elf_Header.e_type <= 0xffff)
        n2print("%s%s\n", dpstr(S_n2dumper_e_type), dpstr(S_n2dumper_Processor_specific_use));
    else {
        n2print("%s: %s\n", dpstr(S_n2dumper_Error), dpstr(S_n2dumper_Unknown_Elf_Format));
        throw DpEx_UnknownElfFormat;                // unknown ELF format
    }

    // CPU type
    const char * cpuname = dpGetElfCpuName(elf_Header.e_machine);
    if (cpuname != NULL)
        n2print("%s%s\n", dpstr(S_n2dumper_e_machine), cpuname);
    else
        n2print("%s0x%04x (%s)\n", dpstr(S_n2dumper_e_machine), elf_Header.e_machine, dpstr(S_n2dumper_unknown));

    // version
    if (elf_Header.e_version == 1)
        n2print("%s%d (%s)\n", dpstr(S_n2dumper_e_version), elf_Header.e_version, dpstr(S_n2dumper_current));
    else
        n2print("%s%d (%s)\n", dpstr(S_n2dumper_e_version), elf_Header.e_version, dpstr(S_n2dumper_invalid));

    // entry
    if (ident.flag.Class == CLASS_ELF64) {        // elf64
        if ( elf_Header.e_entry >= 0x100000000 )
            n2print("%s0x%s\n", dpstr(S_n2dumper_e_entry), dpll2Hex(elf_Header.e_entry));
        else
            n2print("%s0x%08X\n", dpstr(S_n2dumper_e_entry), (unsigned)(elf_Header.e_entry));
    }
    else {
        n2print("%s0x%08X\n", dpstr(S_n2dumper_e_entry), (unsigned)(elf_Header.e_entry));
    }

    // Program Header Table offset
    if (ident.flag.Class == CLASS_ELF64) {        // elf64
        if ( elf_Header.e_phoff >= 0x100000000 )
            n2print("%s0x%s\n", dpstr(S_n2dumper_e_phoff), dpll2Hex(elf_Header.e_phoff));
        else
            n2print("%s0x%08X\n", dpstr(S_n2dumper_e_phoff), (unsigned)(elf_Header.e_phoff));
    }
    else {
        n2print("%s0x%08X\n", dpstr(S_n2dumper_e_phoff), (unsigned)(elf_Header.e_phoff));
    }

    // Section Header Table offset
    if (ident.flag.Class == CLASS_ELF64) {        // elf64
        if ( elf_Header.e_shoff >= 0x100000000 )
            n2print("%s0x%s\n", dpstr(S_n2dumper_e_shoff), dpll2Hex(elf_Header.e_shoff));
        else
            n2print("%s0x%08X\n", dpstr(S_n2dumper_e_shoff), (unsigned)(elf_Header.e_shoff));
    }
    else {
        n2print("%s0x%08X\n", dpstr(S_n2dumper_e_shoff), (unsigned)(elf_Header.e_shoff));
    }

    // CPU flag
    if (elf_Header.e_flags == 0)
        n2print("%s%d\n", dpstr(S_n2dumper_e_flags), elf_Header.e_flags);
    else
        n2print("%s08X\n", dpstr(S_n2dumper_e_flags), elf_Header.e_flags);

    // This member holds the ELF header's size in bytes
    n2print("%s%d (in bytes)\n", dpstr(S_n2dumper_e_ehsize), elf_Header.e_ehsize);

    // Size of program headers
    n2print("%s%d (in bytes)\n", dpstr(S_n2dumper_e_phentsize), elf_Header.e_phentsize);

    // Number of program headers
    n2print("%s%d\n", dpstr(S_n2dumper_e_phnum), elf_Header.e_phnum);

    // Size of section headers
    n2print("%s%d (in bytes)\n", dpstr(S_n2dumper_e_shentsize), elf_Header.e_shentsize);

    // Number of section headers
    n2print("%s%d\n", dpstr(S_n2dumper_e_shnum), elf_Header.e_shnum);

    // Section header string table index
    n2print("%s%d\n", dpstr(S_n2dumper_e_shstrndx), elf_Header.e_shstrndx);
    
    return;
}

static const char* dpGetElfAbiName(unsigned char abi)
{
    switch (abi) 
    {
    case 0x00:      return "System V";
    case 0x01:      return "HP-UX";
    case 0x02:      return "NetBSD";
    case 0x03:      return "GNU/Linux";
    case 0x04:      return "GNU/Hurd";
    //case 0x05:
    case 0x06:      return "Solaris";
    case 0x07:      return "AIX";
    case 0x08:      return "IRIX";
    case 0x09:      return "FreeBSD";
    case 0x0A:      return "TRU64";
    case 0x0B:      return "Novell - Modesto";
    case 0x0C:      return "OpenBSD";
    case 0x0D:      return "VMS - OpenVMS";
    case 0x0E:      return "HP - Non-Stop Kernel";
    case 0x0F:      return "AROS";
    case 0x10:      return "FenixOS";
    //
    case 0x40:      return "Bare-metal C6000";
    case 0x41:      return "Linux C6000";
    case 0x61:      return "ARM";
    case 0xff:      return "Standalone application (embedded)";
    default:        return NULL;
    }

}

static const char * dpGetElfCpuName(unsigned short machine)
{
    switch (machine)
    {
    case 0:         return "none";
    case 3:         return "i386";
    case 6:         return "i486";
    case 62:        return "x86-64";
    case 40:        return "ARM";
    case 50:        return "IA-64";
    case 20:        return "PowerPC";
    case 21:        return "64-bit PowerPC";
    case 2:         return "SPARC";
    case 18:        return "SPARC v8+";
    case 43:        return "SPARC v9 64-bit";
    case 4:         return "Motorola 68000";
    case 5:         return "Motorola 88000";
    case 52:        return "Motorola Coldfire";
    case 8:         return "MIPS R3000";
    case 10:        return "MIPS R4000";
    case 42:        return "SuperH SH";
    case 190:       return "NVIDIA CUDA";
    ////////////////
    case 1:         return "AT&T WE 32100";
    case 7:         return "Intel 80860";
    case 9:         return "IBM S370";
    case 22:        return "IBM S390";
    case 165:       return "Intel 8051";
    case 83:        return "Atmel AVR";
    case 185:       return "Atmel AVR 32-bit";
    ////////////////
    default:        return NULL;
    }
}

static void dpReadElfSectionHeaderFromFile(FILE *fp)
{
    size_t uTotalSize, i;
    unsigned char *pbHeadData;
    const unsigned char *pbc;
    dp_fseek64_in_filepart(fp, elf_Header.e_shoff, SEEK_SET);
    uTotalSize = elf_Header.e_shentsize * elf_Header.e_shnum;
    pbHeadData = new unsigned char [uTotalSize + 16];
    if ( pbHeadData == NULL ) {
        throw DpEx_CannotAllocMemory;
    }
    dp_fread(pbHeadData, 1, uTotalSize, fp);

    elf64_sechdr = new Elf64_Shdr[elf_Header.e_shnum];
    if (elf64_sechdr == NULL) 
        throw DpEx_CannotAllocMemory;

    if (ident.flag.Class == CLASS_ELF32) {
        pbc = pbHeadData;
        for (i = 0; i < elf_Header.e_shnum; i++) {
            elf64_sechdr[i].sh_name =       dpAutoSwap32(*((unsigned*)(pbc+0)));
            elf64_sechdr[i].sh_type =       dpAutoSwap32(*((unsigned*)(pbc+4)));
            elf64_sechdr[i].sh_flags =      dpAutoSwap32(*((unsigned*)(pbc+8)));
            elf64_sechdr[i].sh_addr =       dpAutoSwap32(*((unsigned*)(pbc+12)));
            elf64_sechdr[i].sh_offset =     dpAutoSwap32(*((unsigned*)(pbc+16)));
            elf64_sechdr[i].sh_size =       dpAutoSwap32(*((unsigned*)(pbc+20)));
            elf64_sechdr[i].sh_link =       dpAutoSwap32(*((unsigned*)(pbc+24)));
            elf64_sechdr[i].sh_info =       dpAutoSwap32(*((unsigned*)(pbc+28)));
            elf64_sechdr[i].sh_addralign =  dpAutoSwap32(*((unsigned*)(pbc+32)));
            elf64_sechdr[i].sh_entsize =    dpAutoSwap32(*((unsigned*)(pbc+36)));
            pbc += elf_Header.e_shentsize;
        }
    }
    else if (ident.flag.Class == CLASS_ELF64) {
        pbc = pbHeadData;
        for (i = 0; i < elf_Header.e_shnum; i++) {
            elf64_sechdr[i].sh_name =       dpAutoSwap32(*((unsigned*)(pbc+0)));
            elf64_sechdr[i].sh_type =       dpAutoSwap32(*((unsigned*)(pbc+4)));
            elf64_sechdr[i].sh_flags =      dpAutoSwap64(*((unsigned long long*)(pbc+8)));
            elf64_sechdr[i].sh_addr =       dpAutoSwap64(*((unsigned long long*)(pbc+16)));
            elf64_sechdr[i].sh_offset =     dpAutoSwap64(*((unsigned long long*)(pbc+24)));
            elf64_sechdr[i].sh_size =       dpAutoSwap64(*((unsigned long long*)(pbc+32)));
            elf64_sechdr[i].sh_link =       dpAutoSwap32(*((unsigned*)(pbc+40)));
            elf64_sechdr[i].sh_info =       dpAutoSwap32(*((unsigned*)(pbc+44)));
            elf64_sechdr[i].sh_addralign =  dpAutoSwap64(*((unsigned long long*)(pbc+48)));
            elf64_sechdr[i].sh_entsize =    dpAutoSwap64(*((unsigned long long*)(pbc+56)));
            pbc += elf_Header.e_shentsize;
        }
    }
    delete[] pbHeadData;
}

static const char* dpGetElfSectionTypeText(unsigned type)
{
    switch (type) 
    {
    case 0:             return "NONE";
    case 1:             return "PROGBITS";
    case 2:             return "SYMTAB";
    case 3:             return "STRTAB";
    case 4:             return "RELA";
    case 5:             return "HASH";
    case 6:             return "DYNAMIC";
    case 7:             return "NOTE";
    case 8:             return "NOBITS";
    case 9:             return "REL";
    case 10:            return "SHLIB";
    case 11:            return "DYNSYM";
    case 14:            return "INIT_ARRAY";
    case 15:            return "FINI_ARRAY";
    case 16:            return "PREINIT_ARRAY";
    case 17:            return "GROUP";
    case 18:            return "SYMTAB_SHNDX";

    case 0x6ffffffd:    return "VERDEF";        // GNU new
    case 0x6ffffffe:    return "VERNEED";
    case 0x6fffffff:    return "VERSYM";
    case 0x6ffffff0:	return "VERSYM";
    case 0x6ffffffc:	return "VERDEF";
    case 0x7ffffffd:	return "AUXILIARY";
    case 0x7fffffff:	return "FILTER";
    case 0x6ffffff7:    return "GNU_LIBLIST";
    case 0x6ffffff6:    return "GNU_HASH";
    case 0x6ffffff5:    return "GNU_ATTR";
    case 0x6fff4700:    return "INCREMENTAL_INPUTS";

    case 0x60000000:    return "LOOS";
    //case 0x6FFFFFFF:    return "HIOS";
    case 0x70000000:    return "LOPROC";
    //case 0x7FFFFFFF:    return "HIPROC";
    case 0X80000000:    return "LOUSER";
    case 0X8FFFFFFF:    return "HIUSER";
    default:            return "unknown";
    }
}

static const char *dpGetElfSectionFlagsText(unsigned long long flags)
{
    static char ftext[32];
    size_t count = 0;
    if (flags & 0x00000001)             // bit0  - Write
        ftext[count++] = 'W';           // 
    if (flags & 0x00000002)             // bit1  - Alloc
        ftext[count++] = 'A';           // 
    if (flags & 0x00000004)             // bit2  - eXec(executable)
        ftext[count++] = 'X';           // 
    if (flags & 0x00000010)             // bit4  - Merge
        ftext[count++] = 'M';           // 
    if (flags & 0x00000020)             // bit5  - Strings
        ftext[count++] = 'S';           // 
    if (flags & 0x00000040)             // bit6  - Info link (sh_info holds section header table index)
        ftext[count++] = 'I';           // 
    if (flags & 0x00000080)             // bit7  - Link order (Preserve section ordering when linking)
        ftext[count++] = 'L';           // 
    if (flags & 0x00000100)             // bit8  - OS specific processing required
        ftext[count++] = 'O';           // 
    if (flags & 0x00000200)             // bit9  - Group (Member of a section group)
        ftext[count++] = 'G';           // 
    if (flags & 0x00000400)             // bit10 - TLS
        ftext[count++] = 'T';           // 
    if ((flags&0x0F000000)==0x0F000000) // OS specific
        ftext[count++] = 'o';           // 
    if ((flags&0xF0000000)==0xF0000000) // Processor-specific use
        ftext[count++] = 'p';           // 
    else {
        if (flags & 0x80000000)         // Exclude (Linker exclude this section from executable file)
            ftext[count++] = 'E';       // 
    }
    ftext[count++] = 0;
    return ftext;
}

static void dpExplainElfSectionHeaderAllUsedLetter()
{
    size_t i;
    unsigned long long totalFlags = 0;
    bool isProcessorUseFlag = false;
    bool isExcludeFlag = false;
    for (i = 0; i < elf_Header.e_shnum; i++) 
    {
        unsigned long long flags;
        flags = elf64_sechdr[i].sh_flags;
        //
        if ((flags&0xF0000000)==0xF0000000) // Processor-specific use
            isProcessorUseFlag = true;      // 
        else {
            if (flags & 0x80000000)         // Exclude (Linker exclude this section from executable file)
                isExcludeFlag = true;       // 
        }
        totalFlags |= flags;
    }

    if (totalFlags == 0 && !isProcessorUseFlag && !isExcludeFlag)
        return;
    else
        n2print("%s :\n", dpstr(S_n2dumper_Flags_letter));

    if (totalFlags & 0x00000001)             // bit0  - Write
        n2print("      W - %s\n", dpstr(S_n2dumper_Writable_section));
    if (totalFlags & 0x00000002)             // bit1  - Alloc
        n2print("      A - %s\n", dpstr(S_n2dumper_Occupies_memory));
    if (totalFlags & 0x00000004)             // bit2  - eXec(executable)
        n2print("      X - %s\n", dpstr(S_n2dumper_Executable_section));
    if (totalFlags & 0x00000010)             // bit4  - Merge
        n2print("      M - %s\n", dpstr(S_n2dumper_can_be_merged));
    if (totalFlags & 0x00000020)             // bit5  - Strings
        n2print("      S - %s\n", dpstr(S_n2dumper_Contains_strings));
    if (totalFlags & 0x00000040)             // bit6  - Info link (sh_info holds section header table index)
        n2print("      I - %s\n", dpstr(S_n2dumper_sh_info_is_table_index));
    if (totalFlags & 0x00000080)             // bit7  - Link order (Preserve section ordering when linking)
        n2print("      L - %s\n", dpstr(S_n2dumper_Preserve_section_ordering));
    if (totalFlags & 0x00000100)             // bit8  - OS specific processing required
        n2print("      O - %s\n", dpstr(S_n2dumper_OS_specific_processing_required));
    if (totalFlags & 0x00000200)             // bit9  - Group (Member of a section group)
        n2print("      G - %s\n", dpstr(S_n2dumper_section_group));
    if (totalFlags & 0x00000400)             // bit10 - TLS
        n2print("      T - %s\n", dpstr(S_n2dumper_section_is_TLS));
    if ((totalFlags&0x0F000000)==0x0F000000) // OS specific
        n2print("      o - %s\n", dpstr(S_n2dumper_OS_specific_semantics));
    if (isProcessorUseFlag)
        n2print("      p - %s\n", dpstr(S_n2dumper_Processor_specific_semantics));
    if (isExcludeFlag)
        n2print("      E - %s\n", dpstr(S_n2dumper_exclude_this_section));
}

static void dpReadElfSectionHeader(FILE *fp)
{
    size_t i, j;
    char * shstrtab;
    size_t uMaxLenOfType, uIDMaxLen, uMaxAddrLen, uMaxOffLen, uMaxFlagLen;
    size_t uMaxSizeLen, uMaxEntrySizeLen, uMaxAlignLen, uMaxLinkLen, uMaxInfoLen;
    bool is64BitAddr = false;
    bool is64BitOff = false;
    bool is64BitSize = false;
    size_t count;                   // counter for print 
    char otext[256];

    n2print("\n%s: \n", dpstr(S_n2dumper_Section_Headers));
    dpReadElfSectionHeaderFromFile(fp);

    shstrtab = NULL;
    if (elf_Header.e_shstrndx && elf_Header.e_shstrndx < elf_Header.e_shnum) // Load Section Header String Table
    {
        unsigned long long offset;
        size_t size;
        offset = elf64_sechdr[elf_Header.e_shstrndx].sh_offset;
        size = elf64_sechdr[elf_Header.e_shstrndx].sh_size;
        dp_fseek64_in_filepart(fp, offset, SEEK_SET);
        shstrtab = new char[size+16];
        if (shstrtab == NULL)
            throw DpEx_CannotAllocMemory;
        dp_fread(shstrtab, 1, size, fp);
    }
    else 
    {
        shstrtab = new char[16];
        if (shstrtab == NULL)
            throw DpEx_CannotAllocMemory;
        shstrtab[0] = 0;
        for (i = 0; i < elf_Header.e_shnum; i++)
            elf64_sechdr[i].sh_name = 0;
    }
    
    // get max type length
    uMaxLenOfType = 0;
    for (i = 0; i < elf_Header.e_shnum; i++) {
        size_t len;
        len = strlen(dpGetElfSectionTypeText(elf64_sechdr[i].sh_type));
        if ( uMaxLenOfType < len )
            uMaxLenOfType = len;
    }
    
    // get ID max length
    if (elf_Header.e_shnum >= 10000)
        uIDMaxLen = 5;
    else if (elf_Header.e_shnum >= 1000)
        uIDMaxLen = 4;
    else
        uIDMaxLen = 3;

    // get max Entry size length
    size_t maxEntrySize = 0;
    for (i = 0; i < elf_Header.e_shnum; i++) {
        size_t es;
        es = elf64_sechdr[i].sh_entsize;
        if ( maxEntrySize < es )
            maxEntrySize = es;
    }
    if (maxEntrySize >= 1000000)
        uMaxEntrySizeLen = 20;
    else if (maxEntrySize >= 100000)
        uMaxEntrySizeLen = 6;
    else if (maxEntrySize >= 10000)
        uMaxEntrySizeLen = 5;
    else if (maxEntrySize >= 1000)
        uMaxEntrySizeLen = 4;
    else if (maxEntrySize >= 100)
        uMaxEntrySizeLen = 3;
    else 
        uMaxEntrySizeLen = 2;

    // get max align size length
    size_t maxAlignSize = 0;
    for (i = 0; i < elf_Header.e_shnum; i++) {
        size_t as;
        as = elf64_sechdr[i].sh_addralign;
        if ( maxAlignSize < as )
            maxAlignSize = as;
    }
    if (maxAlignSize >= 1000000)
        uMaxAlignLen = 20;
    else if (maxAlignSize >= 100000)
        uMaxAlignLen = 6;
    else if (maxAlignSize >= 10000)
        uMaxAlignLen = 5;
    else if (maxAlignSize >= 1000)
        uMaxAlignLen = 4;
    else if (maxAlignSize >= 100)
        uMaxAlignLen = 3;
    else 
        uMaxAlignLen = 2;

    // get max link length
    unsigned maxLink = 0;
    for (i = 0; i < elf_Header.e_shnum; i++) {
        size_t link;
        link = elf64_sechdr[i].sh_link;
        if ( maxLink < link )
            maxLink = link;
    }
    if (maxLink >= 0x1000000)
        uMaxLinkLen = 10;
    else if (maxLink >= 0x10000)
        uMaxLinkLen = 8;
    else if (maxLink >= 0x100)
        uMaxLinkLen = 6;
    else  
        uMaxLinkLen = 4;

    // get max info length
    unsigned maxInfo = 0;
    for (i = 0; i < elf_Header.e_shnum; i++) {
        size_t info;
        info = elf64_sechdr[i].sh_info;
        if ( maxInfo < info )
            maxInfo = info;
    }
    if (maxInfo >= 0x1000000)
        uMaxInfoLen = 10;
    else if (maxInfo >= 0x10000)
        uMaxInfoLen = 8;
    else if (maxInfo >= 0x100)
        uMaxInfoLen = 6;
    else  
        uMaxInfoLen = 4;

    // get flags max length
    unsigned maxFlag = 0;
    for (i = 0; i < elf_Header.e_shnum; i++) {
        size_t flaglen;
        flaglen = strlen(dpGetElfSectionFlagsText(elf64_sechdr[i].sh_flags));
        if ( maxFlag < flaglen )
            maxFlag = flaglen;
    }
    uMaxFlagLen = maxFlag+2;
    
    // ELF-64 addr/offset/size max length
    if  (ident.flag.Class == CLASS_ELF64)
    {
        for (i = 0; i < elf_Header.e_shnum; i++) {
            if (elf64_sechdr[i].sh_addr >= 0x100000000) {
                is64BitAddr = true;
                break;
            }
        }
        for (i = 0; i < elf_Header.e_shnum; i++) {
            if (elf64_sechdr[i].sh_offset >= 0x100000000) {
                is64BitOff = true;
                break;
            }
        }
        for (i = 0; i < elf_Header.e_shnum; i++) {
            if (elf64_sechdr[i].sh_size >= 0x100000000) {
                is64BitSize = true;
                break;
            }
        }
        if (is64BitAddr)
            uMaxAddrLen = 18;
        else
            uMaxAddrLen = 10;
        if (is64BitOff)
            uMaxOffLen = 18;
        else
            uMaxOffLen = 10;
        if (is64BitSize)
            uMaxSizeLen = 18;
        else
            uMaxSizeLen = 10;
    }
    else  if (ident.flag.Class == CLASS_ELF32) {
        uMaxAddrLen = 10;
        uMaxOffLen = 10;
        uMaxSizeLen = 10;
    }

    // output title
    count = 0;
    memset(&otext[count], 0x20, uIDMaxLen+1);
    otext[count+uIDMaxLen+1] = 0;
    otext[0] = '#';
    count += (uIDMaxLen+1);

    // type
    memset(&otext[count], 0x20, uMaxLenOfType+1);
    otext[count+uMaxLenOfType+1] = 0;
    memcpy(&otext[count], "type", sizeof("type")-1);
    count += (uMaxLenOfType+1);

    // Address
    memset(&otext[count], 0x20, uMaxAddrLen+1);
    otext[count+uMaxAddrLen+1] = 0;
    memcpy(&otext[count], "Address", sizeof("Address")-1);
    count += (uMaxAddrLen+1);

    // offset
    memset(&otext[count], 0x20, uMaxOffLen+1);
    otext[count+uMaxOffLen+1] = 0;
    memcpy(&otext[count], "Offset", sizeof("Offset")-1);
    count += (uMaxOffLen+1);

    // size
    memset(&otext[count], 0x20, uMaxSizeLen+1);
    otext[count+uMaxSizeLen+1] = 0;
    memcpy(&otext[count], "Size", sizeof("Size")-1);
    count += (uMaxSizeLen+1);

    // entry size
    memset(&otext[count], 0x20, uMaxEntrySizeLen+1);
    otext[count+uMaxEntrySizeLen+1] = 0;
    memcpy(&otext[count], "ES", sizeof("ES")-1); 
    count += (uMaxEntrySizeLen+1);

    // align size
    memset(&otext[count], 0x20, uMaxAlignLen+1);
    otext[count+uMaxAlignLen+1] = 0;
    memcpy(&otext[count], "AL", sizeof("AL")-1);
    count += (uMaxAlignLen+1);

    // link
    memset(&otext[count], 0x20, uMaxLinkLen+1);
    otext[count+uMaxLinkLen+1] = 0;
    memcpy(&otext[count], "link", sizeof("link")-1);
    count += (uMaxLinkLen+1);

    // info
    memset(&otext[count], 0x20, uMaxInfoLen+1);
    otext[count+uMaxInfoLen+1] = 0;
    memcpy(&otext[count], "info", sizeof("info")-1);
    count += (uMaxInfoLen+1);

    // flags
    memset(&otext[count], 0x20, uMaxFlagLen+1);
    otext[count+uMaxFlagLen+1] = 0;
    memcpy(&otext[count], "flag", sizeof("flag")-1);
    count += (uMaxFlagLen+1);

    // name
    strcat(otext, " Section-Name");
    size_t alllen = strlen(otext);

    // show section info title
    for (i = 0; i< alllen; i++)
        n2print("%c", '-');
    n2print("\n");
    n2print("%s\n", otext);
    for (i = 0; i< alllen; i++)
        n2print("%c", '-');
    n2print("\n");

    // output
    for (i = 0; i < elf_Header.e_shnum; i++)
    {
        char ttext[32];
        // ID
        count = 0;
        memset(&otext[count], 0x20, uIDMaxLen+1);
        otext[count+uIDMaxLen+1] = 0;
        sprintf(ttext, "%d", i);
        for (j = 0; j < strlen(ttext); j++)
            otext[count+j] = ttext[j]; 
        count += (uIDMaxLen+1);

        // type
        const char* typestr = dpGetElfSectionTypeText(elf64_sechdr[i].sh_type);
        memset(&otext[count], 0x20, uMaxLenOfType+1);
        otext[count+uMaxLenOfType+1] = 0;
        for (j = 0; j < strlen(typestr); j++)
            otext[count+j] = typestr[j]; 
        count += (uMaxLenOfType+1);

        // Address
        memset(&otext[count], 0x20, uMaxAddrLen+1);
        otext[count+uMaxAddrLen+1] = 0;
        if (is64BitAddr)
            sprintf(ttext, "0x%s", dpll2Hex(elf64_sechdr[i].sh_addr));
        else 
            sprintf(ttext, "0x%08X", (unsigned)(elf64_sechdr[i].sh_addr));
        for (j = 0; j < strlen(ttext); j++)
            otext[count+j] = ttext[j]; 
        count += (uMaxAddrLen+1);

        // offset
        memset(&otext[count], 0x20, uMaxOffLen+1);
        otext[count+uMaxOffLen+1] = 0;
        if (is64BitOff)
            sprintf(ttext, "0x%s", dpll2Hex(elf64_sechdr[i].sh_offset));
        else
            sprintf(ttext, "0x%08X", (unsigned)(elf64_sechdr[i].sh_offset));
        for (j = 0; j < strlen(ttext); j++)
            otext[count+j] = ttext[j]; 
        count += (uMaxOffLen+1);

        // size
        memset(&otext[count], 0x20, uMaxSizeLen+1);
        otext[count+uMaxSizeLen+1] = 0;
        if (is64BitSize)
            sprintf(ttext, "0x%s", dpll2Hex(elf64_sechdr[i].sh_size));
        else
            sprintf(ttext, "0x%08X", (unsigned)(elf64_sechdr[i].sh_size));
        for (j = 0; j < strlen(ttext); j++)
            otext[count+j] = ttext[j]; 
        count += (uMaxSizeLen+1);

        // entry size
        memset(&otext[count], 0x20, uMaxEntrySizeLen+1);
        otext[count+uMaxEntrySizeLen+1] = 0;
        sprintf(ttext, "%d", (unsigned)(elf64_sechdr[i].sh_entsize));
        for (j = 0; j < strlen(ttext); j++)
            otext[count+j] = ttext[j]; 
        count += (uMaxEntrySizeLen+1);

        // align size
        memset(&otext[count], 0x20, uMaxAlignLen+1);
        otext[count+uMaxAlignLen+1] = 0;
        sprintf(ttext, "%d", (unsigned)(elf64_sechdr[i].sh_addralign));
        for (j = 0; j < strlen(ttext); j++)
            otext[count+j] = ttext[j]; 
        count += (uMaxAlignLen+1);

        // link
        memset(&otext[count], 0x20, uMaxLinkLen+1);
        otext[count+uMaxLinkLen+1] = 0;
        if (uMaxLinkLen == 4)
            sprintf(ttext, "0x%02X", elf64_sechdr[i].sh_link);
        else if (uMaxLinkLen == 6)
            sprintf(ttext, "0x%04X", elf64_sechdr[i].sh_link);
        else if (uMaxLinkLen == 8)
            sprintf(ttext, "0x%06X", elf64_sechdr[i].sh_link);
        else if (uMaxLinkLen == 10)
            sprintf(ttext, "0x%08X", elf64_sechdr[i].sh_link);
        else
            sprintf(ttext, "0x%X", elf64_sechdr[i].sh_link);
        for (j = 0; j < strlen(ttext); j++)
            otext[count+j] = ttext[j]; 
        count += (uMaxLinkLen+1);

        // info
        memset(&otext[count], 0x20, uMaxInfoLen+1);
        otext[count+uMaxInfoLen+1] = 0;
        if (uMaxInfoLen == 4)
            sprintf(ttext, "0x%02X", elf64_sechdr[i].sh_info);
        else if (uMaxInfoLen == 6)
            sprintf(ttext, "0x%04X", elf64_sechdr[i].sh_info);
        else if (uMaxInfoLen == 8)
            sprintf(ttext, "0x%06X", elf64_sechdr[i].sh_info);
        else if (uMaxInfoLen == 10)
            sprintf(ttext, "0x%08X", elf64_sechdr[i].sh_info);
        else
            sprintf(ttext, "0x%X", elf64_sechdr[i].sh_info);
        for (j = 0; j < strlen(ttext); j++)
            otext[count+j] = ttext[j]; 
        count += (uMaxInfoLen+1);

        // flags
        const char * flagStr = dpGetElfSectionFlagsText(elf64_sechdr[i].sh_flags);
        memset(&otext[count], 0x20, uMaxFlagLen+1);
        otext[count+uMaxFlagLen+1] = 0;
        if (strlen(flagStr)) {
            otext[count] = '[';
            for (j = 0; j < strlen(flagStr); j++)
                otext[count+j+1] = flagStr[j]; 
            otext[count+j+1] = ']';
        }
        count += (uMaxFlagLen+1);

        // show section info
        n2print(otext);

        // show section name
        n2print(&shstrtab[elf64_sechdr[i].sh_name]);

        n2print("\n");
    }

    delete[] shstrtab;

    // explain flags letter
    dpExplainElfSectionHeaderAllUsedLetter();
    
}

static void dpReadElfProgramHeaderFromFile(FILE* fp)
{
    size_t uTotalSize, i;
    unsigned char *pbHeadData;
    const unsigned char *pbc;
    dp_fseek64_in_filepart(fp, elf_Header.e_phoff, SEEK_SET);
    uTotalSize = elf_Header.e_phentsize * elf_Header.e_phnum;
    pbHeadData = new unsigned char [uTotalSize + 16];
    if ( pbHeadData == NULL ) {
        throw DpEx_CannotAllocMemory;
    }
    dp_fread(pbHeadData, 1, uTotalSize, fp);

    elf64_prohdr = new Elf64_Phdr[elf_Header.e_phnum];
    if (elf64_prohdr == NULL) 
        throw DpEx_CannotAllocMemory;

    if (ident.flag.Class == CLASS_ELF32) {
        pbc = pbHeadData;
        for (i = 0; i < elf_Header.e_phnum; i++) {
            elf64_prohdr[i].p_type =        dpAutoSwap32(*((unsigned*)(pbc+0)));
            elf64_prohdr[i].p_offset =      dpAutoSwap32(*((unsigned*)(pbc+4)));
            elf64_prohdr[i].p_vaddr =       dpAutoSwap32(*((unsigned*)(pbc+8)));
            elf64_prohdr[i].p_paddr =       dpAutoSwap32(*((unsigned*)(pbc+12)));
            elf64_prohdr[i].p_filesz =      dpAutoSwap32(*((unsigned*)(pbc+16)));
            elf64_prohdr[i].p_memsz =       dpAutoSwap32(*((unsigned*)(pbc+20)));
            elf64_prohdr[i].p_flags =       dpAutoSwap32(*((unsigned*)(pbc+24)));
            elf64_prohdr[i].p_align =       dpAutoSwap32(*((unsigned*)(pbc+28)));
            pbc += elf_Header.e_phentsize;
        }
    }
    else if (ident.flag.Class == CLASS_ELF64) {
        pbc = pbHeadData;
        for (i = 0; i < elf_Header.e_phnum; i++) {
            elf64_prohdr[i].p_type =        dpAutoSwap32(*((unsigned*)(pbc+0)));
            elf64_prohdr[i].p_flags =       dpAutoSwap32(*((unsigned*)(pbc+4)));
            elf64_prohdr[i].p_offset =      dpAutoSwap64(*((unsigned long long*)(pbc+8)));
            elf64_prohdr[i].p_vaddr =       dpAutoSwap64(*((unsigned long long*)(pbc+16)));
            elf64_prohdr[i].p_paddr =       dpAutoSwap64(*((unsigned long long*)(pbc+24)));
            elf64_prohdr[i].p_filesz =      dpAutoSwap64(*((unsigned long long*)(pbc+32)));
            elf64_prohdr[i].p_memsz =       dpAutoSwap64(*((unsigned long long*)(pbc+40)));
            elf64_prohdr[i].p_align =       dpAutoSwap64(*((unsigned long long*)(pbc+48)));
            pbc += elf_Header.e_phentsize;
        }
    }
    delete[] pbHeadData;
}

static char* dpGetElfProHeaderTypeStr(unsigned type)
{
    switch (type) 
    {
    case 0:             return "NULL";
    case 1:             return "LOAD";
    case 2:             return "DYNAMIC";
    case 3:             return "INTERP";
    case 4:             return "NOTE";
    case 5:             return "SHLIB";
    case 6:             return "PHDR";
    case 7:             return "TLS";
    case 0x6474e550:    return "GNU_EH_FRAME";      // Frame unwind information
    case 0x6474e551:    return "GNU_STACK";
    case 0x6474e552:    return "GNU_RELRO";         // Read-only after relocation
    case 0x60000000:    return "LOOS";
    case 0x6fffffff:    return "HIOS";
    case 0x70000000:    return "LOPROC";
    case 0x7fffffff:    return "HIPROC";
    default:            return "unknown ";
    }
}

static const char *dpGetElfProgramHeaderFlagsText(unsigned long flags)
{
    static char ftext[32];
    size_t count = 0;
    if (flags & 0x00000004)             // bit2  - Read
        ftext[count++] = 'R';           // 
    if (flags & 0x00000002)             // bit1  - Write
        ftext[count++] = 'W';           // 
    if (flags & 0x00000001)             // bit0  - Exec
        ftext[count++] = 'X';           // 
    ftext[count++] = 0;
    return ftext;
}

static void dpReadElfProgramHeader(FILE *fp)
{
    size_t i, j, len;
    size_t uMaxTypeLen, uMaxVirtAddrLen, uMaxPhysAddrLen, uMaxOffsetLen, uMaxFileSizeLen;
    size_t uIDMaxLen, uMaxMemSizeLen, uMaxAlignLen, uMaxFlagLen;
    size_t count;                   // counter for print 
    char otext[256];

    if (elf_Header.e_phnum == 0)
        return;
    n2print("\n%s: \n", dpstr(S_n2dumper_Program_Headers));
    dpReadElfProgramHeaderFromFile(fp);

    // get ID max length
    if (elf_Header.e_phnum >= 10000)
        uIDMaxLen = 5;
    else if (elf_Header.e_phnum >= 1000)
        uIDMaxLen = 4;
    else
        uIDMaxLen = 3;

    // get program entry type string max length
    uMaxTypeLen = 0;
    for (i = 0; i < elf_Header.e_phnum; i++) {
        len = strlen(dpGetElfProHeaderTypeStr(elf64_prohdr[i].p_type));
        if (uMaxTypeLen < len)
            uMaxTypeLen = len;
    }

    // offset max length
    bool is64BitOffset = false;
    for (i = 0; i < elf_Header.e_phnum; i++) {
        if (elf64_prohdr[i].p_offset >= 0x100000000) {
            is64BitOffset = true;
            break;
        }
    }
    if (is64BitOffset)
        uMaxOffsetLen = 18;
    else
        uMaxOffsetLen = 10;

    // file size max length
    bool is64BitFileSize = false;
    for (i = 0; i < elf_Header.e_phnum; i++) {
        if (elf64_prohdr[i].p_filesz >= 0x100000000) {
            is64BitFileSize = true;
            break;
        }
    }
    if (is64BitFileSize)
        uMaxFileSizeLen = 18;
    else
        uMaxFileSizeLen = 10;

    // virt address max length
    bool is64BitVirtAddr = false;
    for (i = 0; i < elf_Header.e_phnum; i++) {
        if (elf64_prohdr[i].p_vaddr >= 0x100000000) {
            is64BitVirtAddr = true;
            break;
        }
    }
    if (is64BitVirtAddr)
        uMaxVirtAddrLen = 18;
    else
        uMaxVirtAddrLen = 10;

    // paddr
    bool is64BitPAddr = false;
    for (i = 0; i < elf_Header.e_phnum; i++) {
        if (elf64_prohdr[i].p_paddr >= 0x100000000) {
            is64BitPAddr = true;
            break;
        }
    }
    if (is64BitPAddr)
        uMaxPhysAddrLen = 18;
    else
        uMaxPhysAddrLen = 10;

    // memory size
    bool is64BitMemSize = false;
    for (i = 0; i < elf_Header.e_phnum; i++) {
        if (elf64_prohdr[i].p_memsz >= 0x100000000) {
            is64BitMemSize = true;
            break;
        }
    }
    if (is64BitMemSize)
        uMaxMemSizeLen = 18;
    else
        uMaxMemSizeLen = 10;

    // max align length
    unsigned long long maxAlign = 0;
    for (i = 0; i < elf_Header.e_phnum; i++) {
        if (maxAlign < elf64_prohdr[i].p_align) 
            maxAlign = elf64_prohdr[i].p_align;
    }
    if (maxAlign >= 0x100000000)
        uMaxAlignLen = 18;
    else if (maxAlign >= 0x100000)
        uMaxAlignLen = 10;
    else if (maxAlign >= 0x10000)
        uMaxAlignLen = 8;
    else
        uMaxAlignLen = 6;

    // get max flags length
    unsigned maxFlag = 0;
    for (i = 0; i < elf_Header.e_phnum; i++) {
        size_t flaglen;
        flaglen = strlen(dpGetElfProgramHeaderFlagsText(elf64_prohdr[i].p_flags));
        if ( maxFlag < flaglen )
            maxFlag = flaglen;
    }
    uMaxFlagLen = maxFlag+2;

    // build title
    // id
    count = 0;
    memset(&otext[count], 0x20, uIDMaxLen+1);
    otext[count+uIDMaxLen+1] = 0;
    otext[count] = '#';
    count += (uIDMaxLen+1);

    // type
    memset(&otext[count], 0x20, uMaxTypeLen+1);
    otext[count+uMaxTypeLen+1] = 0;
    memcpy(&otext[count], "type", sizeof("type")-1);
    count += (uMaxTypeLen+1);

    // offset 
    memset(&otext[count], 0x20, uMaxOffsetLen+1);
    otext[count+uMaxOffsetLen+1] = 0;
    memcpy(&otext[count], "offset", sizeof("offset")-1);
    count += (uMaxOffsetLen+1);

    // filesize 
    memset(&otext[count], 0x20, uMaxFileSizeLen+1);
    otext[count+uMaxFileSizeLen+1] = 0;
    memcpy(&otext[count], "FileSize", sizeof("FileSize")-1);
    count += (uMaxFileSizeLen+1);

    // Virtual Address
    memset(&otext[count], 0x20, uMaxVirtAddrLen+1);
    otext[count+uMaxVirtAddrLen+1] = 0;
    memcpy(&otext[count], "VirtAddr", sizeof("VirtAddr")-1);
    count += (uMaxVirtAddrLen+1);

    // Phys Address
    memset(&otext[count], 0x20, uMaxPhysAddrLen+1);
    otext[count+uMaxPhysAddrLen+1] = 0;
    memcpy(&otext[count], "PhysAddr", sizeof("PhysAddr")-1);
    count += (uMaxPhysAddrLen+1);

    // Memory size
    memset(&otext[count], 0x20, uMaxMemSizeLen+1);
    otext[count+uMaxMemSizeLen+1] = 0;
    memcpy(&otext[count], "MemSize", sizeof("MemSize")-1);
    count += (uMaxMemSizeLen+1);

    // align
    memset(&otext[count], 0x20, uMaxAlignLen+1);
    otext[count+uMaxAlignLen+1] = 0;
    memcpy(&otext[count], "Align", sizeof("Align")-1);
    count += (uMaxAlignLen+1);

    // flags
    strcat(&otext[count], "Flags");
    
    // show title
    for (i = 0; i< strlen(otext); i++)
        n2print("%c", '-');
    n2print("\n");
    n2print("%s\n", otext);
    for (i = 0; i< strlen(otext); i++)
        n2print("%c", '-');
    n2print("\n");

    for (i = 0; i < elf_Header.e_phnum; i++)
    {
        char ttext[32];
        count = 0;
        // id
        memset(&otext[count], 0x20, uIDMaxLen+1);
        otext[count+uIDMaxLen+1] = 0;
        sprintf(ttext, "%d", i);
        for (j = 0; j < strlen(ttext); j++)
            otext[count+j] = ttext[j]; 
        count += (uIDMaxLen+1);

        // type
        const char * pbTypeStr = dpGetElfProHeaderTypeStr(elf64_prohdr[i].p_type);
        memset(&otext[count], 0x20, uMaxTypeLen+1);
        otext[count+uMaxTypeLen+1] = 0;
        memcpy(&otext[count], pbTypeStr, strlen(pbTypeStr));
        count += (uMaxTypeLen+1);

        // offset 
        memset(&otext[count], 0x20, uMaxOffsetLen+1);
        otext[count+uMaxOffsetLen+1] = 0;
        if (is64BitOffset)
            sprintf(ttext, "0x%s", dpll2Hex(elf64_prohdr[i].p_offset));
        else
            sprintf(ttext, "0x%08X", (unsigned)(elf64_prohdr[i].p_offset));
        for (j = 0; j < strlen(ttext); j++)
            otext[count+j] = ttext[j]; 
        count += (uMaxOffsetLen+1);

        // filesize 
        memset(&otext[count], 0x20, uMaxFileSizeLen+1);
        otext[count+uMaxFileSizeLen+1] = 0;
        if (is64BitFileSize)
            sprintf(ttext, "0x%s", dpll2Hex(elf64_prohdr[i].p_filesz));
        else
            sprintf(ttext, "0x%08X", (unsigned)(elf64_prohdr[i].p_filesz));
        for (j = 0; j < strlen(ttext); j++)
            otext[count+j] = ttext[j]; 
        count += (uMaxFileSizeLen+1);
        
        // Virtual Address
        memset(&otext[count], 0x20, uMaxVirtAddrLen+1);
        otext[count+uMaxVirtAddrLen+1] = 0;
        if (is64BitVirtAddr)
            sprintf(ttext, "0x%s", dpll2Hex(elf64_prohdr[i].p_vaddr));
        else
            sprintf(ttext, "0x%08X", (unsigned)(elf64_prohdr[i].p_vaddr));
        for (j = 0; j < strlen(ttext); j++)
            otext[count+j] = ttext[j]; 
        count += (uMaxVirtAddrLen+1);

        // Phys Address
        memset(&otext[count], 0x20, uMaxPhysAddrLen+1);
        otext[count+uMaxPhysAddrLen+1] = 0;
        if (is64BitPAddr)
            sprintf(ttext, "0x%s", dpll2Hex(elf64_prohdr[i].p_paddr));
        else
            sprintf(ttext, "0x%08X", (unsigned)(elf64_prohdr[i].p_paddr));
        for (j = 0; j < strlen(ttext); j++)
            otext[count+j] = ttext[j]; 
        count += (uMaxPhysAddrLen+1);

        // Memory size
        memset(&otext[count], 0x20, uMaxMemSizeLen+1);
        otext[count+uMaxMemSizeLen+1] = 0;
        if (is64BitMemSize)
            sprintf(ttext, "0x%s", dpll2Hex(elf64_prohdr[i].p_memsz));
        else
            sprintf(ttext, "0x%08X", (unsigned)(elf64_prohdr[i].p_memsz));
        for (j = 0; j < strlen(ttext); j++)
            otext[count+j] = ttext[j]; 
        count += (uMaxMemSizeLen+1);

        // align
        memset(&otext[count], 0x20, uMaxAlignLen+1);
        otext[count+uMaxAlignLen+1] = 0;
        if (uMaxAlignLen == 18)
            sprintf(ttext, "0x%s", dpll2Hex(elf64_prohdr[i].p_align));
        else if (uMaxAlignLen == 10)
            sprintf(ttext, "0x%08X", (unsigned)(elf64_prohdr[i].p_align));
        else if (uMaxAlignLen == 8)
            sprintf(ttext, "0x%06X", (unsigned)(elf64_prohdr[i].p_align));
        else
            sprintf(ttext, "0x%04X", (unsigned)(elf64_prohdr[i].p_align));
        for (j = 0; j < strlen(ttext); j++)
            otext[count+j] = ttext[j]; 
        count += (uMaxAlignLen+1);

        // flags
        const char * flagStr = dpGetElfProgramHeaderFlagsText(elf64_prohdr[i].p_flags);
        memset(&otext[count], 0x20, uMaxFlagLen+1);
        otext[count+uMaxFlagLen+1] = 0;
        if (strlen(flagStr)) {
            otext[count] = '[';
            for (j = 0; j < strlen(flagStr); j++)
                otext[count+j+1] = flagStr[j]; 
            otext[count+j+1] = ']';
        }
        count += (uMaxFlagLen+1);

        n2print(otext);
        n2print("\n");
    }
    
    // show Program interpreter
    int interidx = -1;
    for (i = 0; i < elf_Header.e_phnum; i++) {
        if (elf64_prohdr[i].p_type == 3) {
            interidx = i;
            break;
        }
    }
    if (interidx >= 0) {
        char * pbInterpreter;
        n2print("  %s : ", dpstr(S_n2dumper_Program_interpreter));
        dp_fseek64_in_filepart(fp, elf64_prohdr[interidx].p_offset, SEEK_SET);
        pbInterpreter = new char[elf64_prohdr[interidx].p_filesz+16];
        if (pbInterpreter == NULL)
            throw DpEx_CannotAllocMemory;
        dp_fread(pbInterpreter, 1, elf64_prohdr[interidx].p_filesz, fp);
        n2print(pbInterpreter);
        n2print("\n");
        delete[] pbInterpreter;
    }
    
    // segment to section mapping
    char * shstrtab = NULL;
    n2print("\n%s : \n", dpstr(S_n2dumper_Section_to_segment_mapping));
    if (elf_Header.e_shstrndx && elf_Header.e_shstrndx < elf_Header.e_shnum) // Load Section Header String Table
    {
        unsigned long long offset;
        size_t size;
        offset = elf64_sechdr[elf_Header.e_shstrndx].sh_offset;
        size = elf64_sechdr[elf_Header.e_shstrndx].sh_size;
        dp_fseek64_in_filepart(fp, offset, SEEK_SET);
        shstrtab = new char[size+16];
        if (shstrtab == NULL)
            throw DpEx_CannotAllocMemory;
        dp_fread(shstrtab, 1, size, fp);
    }
    else 
    {
        shstrtab = new char[16];
        if (shstrtab == NULL)
            throw DpEx_CannotAllocMemory;
        shstrtab[0] = 0;
        for (i = 0; i < elf_Header.e_shnum; i++)
            elf64_sechdr[i].sh_name = 0;
    }

    for (i = 0; i < elf_Header.e_phnum; i++) 
    {
        unsigned long long ph_start, ph_end;
        std::vector <std::string> secnames;
        
        secnames.clear();
        ph_start = elf64_prohdr[i].p_offset;
        ph_end = elf64_prohdr[i].p_filesz + elf64_prohdr[i].p_offset;
        for (j = 0; j < elf_Header.e_shnum; j++) {
            unsigned long long sh_start, sh_end;
            if (elf64_sechdr[j].sh_offset == 0)
                continue;
            sh_start = elf64_sechdr[j].sh_offset;
            sh_end = elf64_sechdr[j].sh_offset + elf64_sechdr[j].sh_size;
            if (sh_start >= ph_start && sh_end <= ph_end)
                secnames.push_back(&shstrtab[elf64_sechdr[j].sh_name]);
        }

        n2print("%03d: ", i);
        for (j = 0; j < secnames.size(); j++)
        {
            n2print(" %s", secnames[j].c_str());
        }
        n2print("\n");
    
    }
    delete[] shstrtab;

    return ;
}

static char * dpGetElfProgramDynlinkEntryStr(unsigned tag)
{
    switch (tag)
    {
    case 0:                     return "NULL";
    case 1:                     return "NEEDED";
    case 2:                     return "PLTRELSZ";
    case 3:                     return "PLTGOT";
    case 4:                     return "HASH";
    case 5:                     return "STRTAB";
    case 6:                     return "SYMTAB";
    case 7:                     return "RELA";
    case 8:                     return "RELASZ";
    case 9:                     return "RELAENT";
    case 10:                    return "STRSZ";
    case 11:                    return "SYMENT";
    case 12:                    return "INIT";
    case 13:                    return "FINI";
    case 14:                    return "SONAME";
    case 15:                    return "RPATH";
    case 16:                    return "SYMBOLIC";
    case 17:                    return "REL";
    case 18:                    return "RELSZ";
    case 19:                    return "RELENT";
    case 20:                    return "PLTREL";
    case 21:                    return "DEBUG";
    case 22:                    return "TEXTREL";
    case 23:                    return "JMPREL";
    case 24:                    return "BIND_NOW";
    case 25:                    return "INIT_ARRAY";
    case 26:                    return "FINI_ARRAY";
    case 27:                    return "INIT_ARRAYSZ";
    case 28:                    return "FINI_ARRAYSZ";
    case 29:                    return "RUNPATH";
    case 30:                    return "FLAGS";
    case 31:                    return "ENCODING";
    case 32:                    return "PREINIT_ARRAY";
    case 33:                    return "PREINIT_ARRAYSZ";
    case 0x6ffffffe:	        return "VERNEED";
    case 0x6fffffff:            return "VERNEEDNUM";
    case 0x6ffffff0:	        return "VERSYM";
    default:                    return "<unknown>";
    }
}

static void dpReadElfProgramDynlinkEntry(FILE* fp)
{
    size_t i, j;
    int iDynSegIdx;
    char ptext[64];
    Elf64_Dyn dynentry;
    char* strtab = NULL;
    std::vector <Elf64_Dyn> dyns;

    if (elf_Header.e_phnum == 0)
        return;

    iDynSegIdx = -1;
    for (i = 0; i < elf_Header.e_phnum; i++)
    {
        if (elf64_prohdr[i].p_type == 2) {
            iDynSegIdx = (int) i;
            break;
        }
    }
    if (iDynSegIdx < 0)
        return;
    dp_fseek64_in_filepart(fp, elf64_prohdr[iDynSegIdx].p_offset, SEEK_SET);
    dyns.clear();
    while (1)
    {
        if (ident.flag.Class == CLASS_ELF32)
        {
            unsigned tag, value;
            dp_fread(&tag, 1, 4, fp);
            dp_fread(&value, 1, 4, fp);
            dynentry.d_tag = dpAutoSwap32(tag);
            dynentry.d_un.d_val = dpAutoSwap32(value);
        }
        else if (ident.flag.Class == CLASS_ELF64)
        {
            unsigned long long tag, value;
            dp_fread(&tag, 1, 8, fp);
            dp_fread(&value, 1, 8, fp);
            dynentry.d_tag = dpAutoSwap64(tag);
            dynentry.d_un.d_val = dpAutoSwap64(value);
        }
        if ((unsigned)dynentry.d_tag == 0)
            break;
        dyns.push_back(dynentry);
    }
    // find the max length of tag type
    size_t maxlen = 0;
    for (i = 0; i < dyns.size(); i++) {
        size_t len = strlen(dpGetElfProgramDynlinkEntryStr((unsigned)dyns[i].d_tag));
        if (maxlen < len)
            maxlen = len;
    }
    // load string table
    int strtabidx = -1;
    int strszidx = -1;
    int prohdridx = -1;
    for (i = 0; i < dyns.size(); i++) {
        if ((unsigned)dyns[i].d_tag == 5) {
            strtabidx = i;
            break;
        }
    }
    for (i = 0; i < dyns.size(); i++) {
        if ((unsigned)dyns[i].d_tag == 10) {
            strszidx = i;
            break;
        }
    }
    if (strtabidx >= 0 && strszidx >= 0){
        for (j = 0; j < elf_Header.e_phnum; j++ ) {
            if (dyns[strtabidx].d_un.d_ptr >= elf64_prohdr[j].p_vaddr  && 
                dyns[strtabidx].d_un.d_ptr < (elf64_prohdr[j].p_vaddr + elf64_prohdr[j].p_memsz) ) 
            {
                prohdridx = j;
                break;
            }
        }
        strtab = new char[(unsigned)(dyns[strszidx].d_un.d_val)+16];
        if (strtab == NULL)
            throw DpEx_CannotAllocMemory;
        if (prohdridx >= 0) {
            dp_fseek64_in_filepart(fp, elf64_prohdr[prohdridx].p_offset + (dyns[strtabidx].d_un.d_ptr - elf64_prohdr[prohdridx].p_vaddr),
                SEEK_SET);
            dp_fread(strtab, 1, (unsigned)(dyns[strszidx].d_un.d_val), fp);
        }
    }

    for (i = 0; i < dyns.size(); i++)
    {
        const char *tagStr;
        n2print("0x%08X ", (unsigned)dyns[i].d_tag);
        tagStr = dpGetElfProgramDynlinkEntryStr((unsigned)dyns[i].d_tag);
        memset(ptext, 0x20, maxlen+1);
        ptext[maxlen+1] = 0;
        memcpy(ptext, tagStr, strlen(tagStr));
        n2print(ptext);
        // content
        switch ((unsigned)dyns[i].d_tag) 
        {
        case 1:         // need *.so filename
            {
                if (strtab && strtabidx >= 0 && strszidx >= 0)
                    n2print(&strtab[(unsigned)dyns[i].d_un.d_val]);
                else
                    n2print("0x%08X", (unsigned)dyns[i].d_un.d_val);
            }
            break;
        default:
            if (dyns[i].d_un.d_val >= 0x100000000)
                n2print("0x%16llX", dyns[i].d_un.d_val);
            else
                n2print("0x%08X", (unsigned)dyns[i].d_un.d_val);
            break;
        }

        n2print("\n");
    }

    if (strtab)
        delete[] strtab;
}


























